package solver

import (
	"fmt"
	"log"
	"slices"
	"strings"
)

func fishLines(lines [9]House, cellCount int) (used bool) {
	for i := 0; i < 9-cellCount; i++ {
		valueCells, valueCounts := sumupCandCells(lines[i])
		for cand, count := range valueCounts {
			if count == 0 || count > cellCount {
				continue
			}
			lineNums := []int{i}
			cellNums := []int{}
			for cellNum, valueCell := range valueCells[cand] {
				if valueCell {
					cellNums = append(cellNums, cellNum)
				}
			}
			for j := i + 1; j < 9; j++ {
				var yes bool
				yes, cellNums = verifyfishLine(&lines[j], cand, cellCount, cellNums)
				if yes {
					lineNums = append(lineNums, j)
					if len(lineNums) == cellCount {
						if clearupFishLines(lines, cand, lineNums, cellNums) {
							fishLog(lines, cand, lineNums, cellNums)
							used = true
						}
						break
					}
				}
			}
		}
	}
	return
}

func verifyfishLine(line *House, cand int, cellCount int, cellNums []int) (yes bool, newCellNums []int) {
	candCellCount := 0
	newCellNums = append(newCellNums, cellNums...)
	for cellNum, cell := range line.cells {
		if cell.solved() {
			continue
		}
		if !cell.candidates[cand] {
			continue
		}
		candCellCount++
		if slices.Contains(cellNums, cellNum) {
			continue
		}
		if len(newCellNums) == cellCount {
			return false, cellNums
		}
		newCellNums = append(newCellNums, cellNum)
	}
	if candCellCount == 0 {
		return false, cellNums
	}
	return true, newCellNums
}

func fishLog(lines [9]House, cand int, lineNums []int, cellNums []int) {
	var b strings.Builder
	var firstHouse, secondHouse string
	if lines[0].HouseType() == 0 { //row
		firstHouse = "r"
		secondHouse = "c"
	} else {
		firstHouse = "c"
		secondHouse = "r"

	}

	fmt.Fprint(&b, firstHouse)
	for _, num := range lineNums {
		fmt.Fprint(&b, num)
	}
	fmt.Fprint(&b, secondHouse)
	for _, num := range cellNums {
		fmt.Fprint(&b, num)
	}
	fmt.Fprintf(&b, " %v ", cand+1)
	switch len(lineNums) {
	case 2:
		fmt.Fprint(&b, "XWing")
	case 3:
		fmt.Fprint(&b, "Swordfish")
	case 4:
		fmt.Fprint(&b, "Jellyfish")
	}

	log.Println(b.String())
}

func clearupFishLines(lines [9]House, cand int, lineNums []int, cellNums []int) (used bool) {
	for lineNum, line := range lines {
		if slices.Contains(lineNums, lineNum) {
			continue
		}
		for _, cellNum := range cellNums {
			cell := line.cells[cellNum]
			if cell.solved() {
				continue
			}
			if cell.removeCandidate(cand) {
				used = true
			}
		}
	}
	return
}

func (g *Grid) XWing() (used bool) {
	if fishLines(g.rows, 2) {
		used = true
	}
	if fishLines(g.cols, 2) {
		used = true
	}
	return
}

func (g *Grid) Swordfish() (used bool) {
	if fishLines(g.rows, 3) {
		used = true
	}
	if fishLines(g.cols, 3) {
		used = true
	}
	return
}

func (g *Grid) Jellyfish() (used bool) {
	if fishLines(g.rows, 4) {
		used = true
	}
	if fishLines(g.cols, 4) {
		used = true
	}
	return
}
